#ifndef _MONITOR_H_
#define _MONITOR_H_

#include "core/Core.h"
#include "core/difftest.h"
#include "device/Bus.h"
#include "device/Timer.h"
#include "device/CLINT.h"
#include "device/Memory.h"
#include "device/Serial.h"
#include "device/Display.h"
#include "device/Keyboard.h"
#include "monitor/Expression.h"

#include <memory>
#include <string>
#include <vector>
#include <functional>

struct Command {
    std::string name;
    std::string description;
    std::function<int()> handler;
};

enum class State {
    RUN,
    END,
    ABORT,
    QUIT,
};

class Monitor {
private:
    bool batch_mode;
    Bus bus;
    Core core;
    Memory* ram = nullptr;
    Serial* serial = nullptr;
    Timer* timer = nullptr;
    Keyboard* keyboard = nullptr;
    Display* display = nullptr;
    CLINT* clint = nullptr;
    Expression* expr = nullptr;
    State state;
    int halt_value;
    std::thread* t = nullptr;
    
    std::vector<Command> cmd_table;
    int cmd_si();
    int cmd_c();
    int cmd_e();
    int cmd_x();
    int cmd_i();
    int cmd_r();
    int cmd_q();
    std::istringstream iss;
    void cmd_table_init();
    void device_init(const char* img_file);
public:
    Monitor(int argc, char *argv[]);
    ~Monitor();
    void run(size_t n = -1);
    int loop();
};

#endif
